/*************************/
/** 仅支持渲染进程引入使用 **/
/************************/

import { IInitJson } from '../../main/init';
import electronUtils from '../../common/electron';
import { IFetchError, TFetchMethod, IFetchOption, IResponseResult } from './type';
import axios, { AxiosResponse, AxiosRequestConfig, AxiosRequestHeaders } from 'axios';
import { requestOnFulfilled, requestOnRejected, responseOnFulfilled, responseOnRejected } from './interceptors';

export * from './type';

let service: IInitJson['service'] | null = null;

// Fetch 实例
const axiosInstance = axios.create({
    timeout: 30000,
    headers: { 'Content-Type': 'application/json' },
});

// 拦截器
axiosInstance.interceptors.request.use(requestOnFulfilled, requestOnRejected);
axiosInstance.interceptors.response.use(responseOnFulfilled, responseOnRejected);

// 业务通用处理（外部处理）
function fetchOnFulfilled<T = void>(response: AxiosResponse): Promise<T> {
    const responseData: T = response.data;
    return Promise.resolve(responseData);
}

// 请求异常处理（内部处理）
function fetchOnRejected(fetchError: IFetchError) {
    switch (fetchError.type) {
        case 'request': {
            // 404
            // 503
            // ...
            console.error('fetch request error -> ', fetchError);
            break;
        }

        case 'response': {
            const { message } = fetchError.error;
            if (message.includes('timeout')) {
                // timeout
            } else {
                // 500
                // ...
            }
            console.error('fetch response error -> ', fetchError.error);
            break;
        }
    }

    return Promise.reject();
}

// Fetch
async function fetch<T = void>(method: TFetchMethod, url: string, data?: unknown, headers?: AxiosRequestHeaders, configs?: IFetchOption['configs']): Promise<T> {
    if (!service) {
        const rendererEnv = await electronUtils.getRendererEnv();
        service = rendererEnv.runtime.service;
    }

    const requestConfig: AxiosRequestConfig = { method, url, data, headers, baseURL: `http://localhost:${service?.port}` };

    if (configs?.params && method === 'post') {
        requestConfig.params = configs.params;
    }
    if (configs && typeof configs.withCredentials === 'boolean') {
        requestConfig.withCredentials = configs.withCredentials;
    }

    return axiosInstance
        .request(requestConfig)
        .then(response => fetchOnFulfilled<T>(response))
        .catch(error => fetchOnRejected(error));
}

// Method
export default {
    get<T = void>(option: IFetchOption): Promise<IResponseResult<T>> {
        return fetch('get', option.url, option.data, option.headers, option.configs);
    },
    post<T = void>(option: IFetchOption): Promise<IResponseResult<T>> {
        return fetch('post', option.url, option.data, option.headers, option.configs);
    },
};
